#include "kernel.h"
#include "honeypot.h"
#include "mutex.h"

// a pointer to the memory-mapped I/O region for the network
volatile struct dev_net *dev_net;
unsigned int fake_tail=0;
int t_locks = 0;
int* t_lock = &t_locks;
// ring size
#define RING_SIZE 16
//buffer size
#define BUFFER_SIZE 4096
void network_init()
{
	/* Find out where I/O region is in memory.*/
	for (int i=0; i <16; i++){
		if (bootparams -> devtable[i].type == DEV_TYPE_NETWORK){
			puts("Detected network device...");
			// find a virtual address that maps to this I/O region
			dev_net =physical_to_virtual (bootparams -> devtable[i].start);
			// also allow network interrupts
			set_cpu_status(current_cpu_status() | (1<<(8+INTR_NETWORK)));
			//allocate the ring buffer for receiving packets
			struct dma_ring_slot* ring=(struct dma_ring_slot*) malloc(sizeof (struct dma_ring_slot) * RING_SIZE);
			//set rx_base varaible of dev_net struct be the physical address of the start of this array
			(dev_net -> rx_base) = virtual_to_physical (ring);
            (dev_net -> rx_tail)=0;
            (dev_net -> rx_head)=0;
			//set rx_capacity variable for book-keeping
			(dev_net-> rx_capacity)= RING_SIZE;			
			//for every ring slot inside the ring buffer, allocate a suitablely sized buffer. 
			
			for (int i=0; i<RING_SIZE; i++){
			//	void* space=malloc(BUFFER_SIZE);
                void* space=alloc_pages(1);
				ring[i].dma_base=virtual_to_physical(space);
				ring[i].dma_len=BUFFER_SIZE;
				
			}
			puts("...network driver is ready.");
			return;
		}
		
	}
	
}

// Starts receiving packets!
void network_start_receive(){
	dev_net->cmd = NET_SET_POWER;
	dev_net->data = 1;
	dev_net->cmd = NET_SET_RECEIVE;
	dev_net->data = 1;
}

// If opt != 0, enables interrupts when a new packet arrives.
// If opt == 0, disables interrupts.
void network_set_interrupts(int opt){
	if (opt != 0) {
		dev_net->cmd = NET_SET_INTERRUPTS;
		dev_net->data = 1;
		set_cpu_status(current_cpu_status() | (1 << (8+INTR_NETWORK)));
	}
	else {
		dev_net->cmd = NET_SET_INTERRUPTS;
		dev_net->data = 0;
		set_cpu_status(current_cpu_status() & (0 << (8+INTR_NETWORK)));
	}
}	

// Continually polls for data on the ring buffer. Loops forever!
void network_poll(){
	while (1) {
		network_trap();
	}	
}	
/*int swap(int num){
 int swapped = ((num>>24)&0xff) | // move byte 3 to byte 0
 ((num<<8)&0xff0000) | // move byte 1 to byte 2
 ((num>>8)&0xff00) | // move byte 2 to byte 1
 ((num<<24)&0xff000000; // byte 0 to byte 3
 return swapped;
 }*/
int swap16(unsigned short num){
	unsigned short swapped = (num>>8) | (num<<8);
	return swapped;
}

// Called when a network interrupt occurs.
void network_trap() {
	//int x = intr_disable();	
	//if (x==0){}
	if (dev_net->rx_head != dev_net->rx_tail){
		struct dma_ring_slot *d =(struct dma_ring_slot*) physical_to_virtual(dev_net->rx_base);
		int *addr = (int* )physical_to_virtual(d[(fake_tail % 16)].dma_base);		
        fake_tail+=1;
		//   printf("counter: %d\n", fake_tail);
        //struct honeypot_command_packet *pkt=(struct honeypot_command_packet*) addr;
		//struct packet_header ph =(struct packet_header ) (pkt->headers);
		// int len=ph.ip_len;
        //int len= swap16(ph.ip_len);
		int len=d[fake_tail%16].dma_len;
	    //printf("len: %d\n", len);	
		//  d[dev_net ->rx_tail %16].dma_len= BUFFER_SIZE; 
		//	dev_net->rx_tail = ((dev_net->rx_tail)+1);	
		handle_packet(addr,len);		
	}
	//intr_restore(1);
}	

void tail_incr(void)
{   
	lock(t_lock);
	struct dma_ring_slot *d =(struct dma_ring_slot*) physical_to_virtual(dev_net->rx_base);
	d[dev_net ->rx_tail %16].dma_len= BUFFER_SIZE; 
	dev_net->rx_tail = ((dev_net->rx_tail)+1);
	unlock(t_lock);
}




